Skip to content

[4/n] add stricter typing in JsonPathStack#15

Open
sunshowers wants to merge 8 commits intosunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstackfrom
sunshowers/spr/2n-add-stricter-typing-in-jsonpathstack
Open

[4/n] add stricter typing in JsonPathStack#15
sunshowers wants to merge 8 commits intosunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstackfrom
sunshowers/spr/2n-add-stricter-typing-in-jsonpathstack

Conversation

@sunshowers
Copy link
Copy Markdown
Contributor

A JsonPathStack always has an endpoint at the bottom and a series of schemas above that. We're going to rely on this in upcoming work -- express this constraint in the type system.

Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
@sunshowers sunshowers changed the title [2/n] add stricter typing in JsonPathStack [3/n] add stricter typing in JsonPathStack Feb 6, 2026
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Copy link
Copy Markdown
Collaborator

@ahl ahl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't look very carefully; please let me know if something needs particular scrutiny

Comment thread src/lib.rs
Comment thread src/path.rs Outdated
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.2n-add-stricter-typing-in-jsonpathstack to main May 5, 2026 01:05
sunshowers added a commit that referenced this pull request May 5, 2026
Detect cycles by checking for path segments (with a trailing `/`) rather than just using a raw string prefix. We hit this in Omicron where `AuditLogEntry` was incorrectly detected as a prefix of `AuditLogEntryActor`, hiding incompatible changes.

This is a minimal fix that (I believe) is correct given the current structure. I'm reworking this in #15 to have stronger types so we can think about this in a more principled manner.
@sunshowers sunshowers changed the base branch from main to sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack May 8, 2026 22:42
@sunshowers sunshowers changed the title [3/n] add stricter typing in JsonPathStack [4/n] add stricter typing in JsonPathStack May 8, 2026
@sunshowers sunshowers changed the base branch from sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack to main May 8, 2026 22:44
@sunshowers sunshowers changed the base branch from main to sunshowers/spr/main.4n-add-stricter-typing-in-jsonpathstack May 8, 2026 22:44
Created using spr 1.3.6-beta.1
Comment thread src/compare.rs
Comment on lines +69 to +81
/// Lifecycle of a schema comparison, keyed by `VisitedKey` in
/// [`Compare::visit_state`].
#[derive(Clone, Debug)]
pub(crate) enum VisitState {
/// Comparison is in progress somewhere up the call stack. Re-entering a
/// key in this state means the schema graph has a cycle.
Visiting,
/// Comparison has completed.
Completed {
/// Whether the two schemas were determined to be equal.
equal: bool,
},
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR I replaced the existing cycle detection check, which relied on looking at the stack of schemas, with a more explicit DFS postorder check.

This is equivalent to the old code:

        if old_schema.context().stack().contains_cycle()
            && new_schema.context().stack().contains_cycle()
        {
            return Ok(true);
        }

Why? Basically because having a prefix in the stack is equivalent to being in the visiting state while performing the DFS. The tests added in #23 don't have any output differences, which is a reasonable sign that there aren't any behavior changes here.

I like how explicit the postorder check is, and it also fits quite nicely into visit_state.

Comment thread src/schema.rs
Comment on lines +205 to +217
// Returning `true` on `Visiting` is sound only because the compare
// methods call `schema_push_change` eagerly on detecting a change
// rather than making decisions based on the value returned from this
// function. If that weren't the case -- for example, if there were
// code which did something like:
//
// let inner_eq = self.compare_schema(...)?;
// if !inner_eq {
// self.schema_push_change(...);
// }
//
// Then, relying on `true` here would result in a false negative.
// This invariant must be upheld by all compare methods.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this block -- the old code also returned true, which is correct, but I wanted to reason about this more clearly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants